package com.lsh.ofc.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lsh.base.common.exception.BusinessException;
import com.lsh.ofc.core.constant.Constants;
import com.lsh.ofc.core.dao.OfcObdDetailDAO;
import com.lsh.ofc.core.dao.OfcObdHeadDAO;
import com.lsh.ofc.core.entity.*;
import com.lsh.ofc.core.enums.*;
import com.lsh.ofc.core.exception.EC;
import com.lsh.ofc.core.model.PackageCodeBo;
import com.lsh.ofc.core.redis.RedisTemplate;
import com.lsh.ofc.core.service.*;
import com.lsh.ofc.core.util.OFCUtils;
import com.lsh.ofc.proxy.context.WumartBasicContext;
import com.lsh.ofc.proxy.service.OmsServiceProxy;
import com.lsh.ofc.proxy.util.MethodCallLogCollector;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.*;

/**
 * @author peter
 */
@Service
public class OfcObdServiceImpl implements OfcObdService {

    private static int DISTRIBUTIONWAY_PC_VALUE = 90;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private OfcObdHeadDAO ofcObdHeadDAO;

    @Autowired
    private OfcObdDetailDAO ofcObdDetailDAO;

    @Autowired
    private OfcOrderService ofcOrderService;

    @Autowired
    private OfcSoService ofcSoService;

    @Autowired
    private OfcBillService ofcBillService;

    @Autowired
    private OfcOperateLogService ofcOperateLogService;

    @Autowired
    private OmsServiceProxy omsServiceProxy;

//    @Autowired
//    private WumartBasicService wumartBasicService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OfcTaskService ofcTaskService;

//    @Autowired
//    private KafkaTemplate kafkaTemplate;

    @Override
    public OfcObdHead findOne(OfcObdHead filter, boolean fillDetails) throws BusinessException {
        OfcObdHead obd = this.ofcObdHeadDAO.findOne(filter);
        if (obd == null) {
            return null;
        }
        if (fillDetails) {
            obd.setDetails(this.findDetails(obd.getSoBillCode()));
        }
        return obd;
    }

    @Override
    public List<OfcObdHead> findList(OfcObdHead filter, boolean fillDetails) throws BusinessException {
        List<OfcObdHead> obds = this.ofcObdHeadDAO.findList(filter);
        if (CollectionUtils.isEmpty(obds)) {
            return Collections.emptyList();
        }
        if (fillDetails) {
            for (OfcObdHead obd : obds) {
                obd.setDetails(this.findDetails(obd.getSoBillCode()));
            }
        }

        return obds;
    }

    @Override
    public List<OfcObdHead> findListByOrderCodes(List<Long> orderCodes, boolean fillDetails) throws BusinessException {
        List<OfcObdHead> obds = this.ofcObdHeadDAO.findListByOrderCodes(orderCodes);
        if (CollectionUtils.isEmpty(obds)) {
            return Collections.emptyList();
        }
        if (fillDetails) {
            for (OfcObdHead obd : obds) {
                obd.setDetails(this.findDetails(obd.getSoBillCode()));
            }
        }

        return obds;
    }

    @Override
    public List<OfcObdDetail> findDetails(String soBillCode) throws BusinessException {
        if (!StringUtils.hasLength(soBillCode)) {
            return Collections.emptyList();
        }
        OfcObdDetail param = new OfcObdDetail();
        param.setSoBillCode(soBillCode);
        return this.ofcObdDetailDAO.findList(param);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void create(OfcObdHead obdHead, boolean updateQty, boolean addTaskFlag) throws BusinessException {
        if (obdHead == null) {
            throw EC.ERROR.exception("obdHead 入参订单信息为空！");
        }

        List<OfcObdDetail> details = obdHead.getDetails();
        if (CollectionUtils.isEmpty(details)) {
            throw EC.ERROR.exception("details 入参订单明细为空！");
        }

        String soBillCode = obdHead.getSoBillCode();
        Integer wms = obdHead.getFulfillWms();
        String uuid = UUID.randomUUID().toString();
//        Integer channel = obdHead.getFulfillChannel();
        // 幂等校验
        OfcSoHead filter_so = new OfcSoHead();
        filter_so.setRegionCode(obdHead.getRegionCode());
        filter_so.setWarehouseCode(obdHead.getWarehouseCode());
        filter_so.setSoBillCode(soBillCode);
        filter_so.setFulfillWms(wms);
        filter_so.setSoStatus(SoStatus.DELIVERED.getValue());
        List<OfcSoHead> soHeadList = ofcSoService.findList(filter_so, false);
        if (soHeadList != null && !CollectionUtils.isEmpty(soHeadList)) {
            return;
        }

        OfcSoHead filter = new OfcSoHead();
        filter.setRegionCode(obdHead.getRegionCode());
        filter.setWarehouseCode(obdHead.getWarehouseCode());
        filter.setSoBillCode(soBillCode);
        filter.setFulfillWms(wms);
        filter.setSoStatus(SoStatus.CREATED.getValue());
        List<OfcSoHead> sos = ofcSoService.findList(filter, true);
        if (CollectionUtils.isEmpty(sos)) {
            throw EC.SO_ORDER_NOT_EXIST.exception("soBillCode = [" + soBillCode + "] ，WMS = " + wms);
        }
        if (1 != sos.size()) {
            throw EC.SO_DUPLICATE.exception("soBillCode = [" + soBillCode + "]，WMS = [" + wms + "]");
        }

        OfcSoHead so = sos.get(0);
        String soCode = so.getSoCode();
        List<OfcSoDetail> soDetails = so.getDetails();
        if (CollectionUtils.isEmpty(soDetails)) {
            EC.SO_DETAILS_IS_EMPTY.exception("soBillCode = [" + soBillCode + "]SO单号=" + soCode + "，WMS=" + wms);
        }
        MethodCallLogCollector.business(so.getSoBillCode(), 20);

        OfcObdHead filterObd = new OfcObdHead();
        filterObd.setSoBillCode(soBillCode);
        filterObd.setFulfillWms(wms);
        OfcObdHead entity = this.findOne(filterObd, false);
        if (entity != null) {
            if (entity.getTotalSkuDeliverQty().compareTo(obdHead.getTotalSkuDeliverQty()) != 0) {
                //TODO:预警
                throw EC.SO_OBD_IS_ERROR.exception("soBillCode = [" + soBillCode + "][SO单号=" + soCode + "]已存在OBD发货数据, 但当前PUSH数量[" + obdHead.getTotalSkuDeliverQty() + "]与既有数量[" + entity.getTotalSkuDeliverQty() + "]不一致！");
            }

            logger.info("OBD发货数据已存在，SO单号 = [" + soCode + "]");
            return;
        }

        Map<String, OfcSoDetail> skuCodeMap = new HashMap<>((int) ((soDetails.size() + 1) / 0.75));
        Map<String, BigDecimal> orderSupplyCodeQtyMap = new HashMap<>((int) ((soDetails.size() + 1) / 0.75));
        Map<Integer, OfcSoDetail> itemNoMap = new HashMap<>((int) ((soDetails.size() + 1) / 0.75));
        Integer fulfillChannel = so.getFulfillChannel();
        for (OfcSoDetail item : soDetails) {
            skuCodeMap.put(item.getSkuSupplyCode(), item);
            if (fulfillChannel.equals(FulfillChannel.WUMART_OFC.getValue())) {
                itemNoMap.put(item.getItemNo(), item);
            } else {
                if (item.getItemCode() == 0) {
                    itemNoMap.put(item.getItemNo(), item);
                } else {
                    itemNoMap.put(item.getItemCode(), item);
                }
            }

            BigDecimal qty = orderSupplyCodeQtyMap.get(item.getSkuSupplyCode());
            BigDecimal orderQty = item.getSkuOrderQty();
            if (qty == null) {
                qty = orderQty;
            } else {
                qty = qty.add(orderQty);
            }

            orderSupplyCodeQtyMap.put(item.getSkuSupplyCode(), qty);
        }

        JSONObject soExt = JSON.parseObject(so.getExt());
        Integer lgortType = soExt.getInteger(Constants.SO_H_LGORT_TYPE);
        boolean needValidateQty = this.needValidateQty(so, lgortType);
        if (needValidateQty) {
            if (obdHead.getTotalSkuDeliverQty().compareTo(so.getTotalSkuOrderQty()) > 0) {
                throw EC.SO_OBD_IS_ERROR.exception("soBillCode 单号 = [" + soBillCode + "] ，WMS=" + wms + " , 发货总数大于订单总数");
            }
        }

        // 处理KG称重商品信息
        Map<String, List<BigDecimal>> supplySkuCodePackageWeightMap = new HashMap<>();
        Map<String, BigDecimal> supplyCodeTotalWeightMap = new HashMap<>();
        this.dealPackageWeight(obdHead, supplySkuCodePackageWeightMap, supplyCodeTotalWeightMap);

        Map<String, BigDecimal> obdSupplyCodeQtyMap = new HashMap<>();
        Long orderCode = so.getOrderCode();
        String billCode = so.getSoBillCode();
        Long venderId = so.getVenderId();
        obdHead.setSoBillCode(billCode);
        obdHead.setOrderCode(orderCode);
        obdHead.setRegionCode(so.getRegionCode());
        obdHead.setWarehouseCode(so.getWarehouseCode());
        obdHead.setWarehouseName(so.getWarehouseName());
        obdHead.setSupplierId(so.getSupplierId());
        obdHead.setSupplierDc(so.getSupplierDc());
        obdHead.setSupplierOrg(so.getSupplierOrg());
        obdHead.setSupplierGroup(so.getSupplierGroup());
        obdHead.setSupplierCode(so.getSupplierCode());
        obdHead.setFulfillWms(so.getFulfillWms());
        obdHead.setFulfillChannel(so.getFulfillChannel());
        obdHead.setSoCode(so.getSoCode());
        obdHead.setObdCode(obdHead.getObdCode());
        obdHead.setTotalSkuOrderQty(so.getTotalSkuOrderQty());
        obdHead.setTotalSkuSupplyQty(so.getTotalSkuSupplyQty());
        obdHead.setValid(Valid.enable.getValue());
        BigDecimal costAmount = BigDecimal.ZERO;
        BigDecimal costNtAmount = BigDecimal.ZERO;
        // TODO 2019-09-08
        obdHead.setVenderId(venderId);

        Integer fil = so.getFulfillChannel();
        List<OfcObdDetail> obdDetails = new ArrayList<>();
        for (OfcObdDetail detail : details) {
            String skuSupplyCode = detail.getSkuSupplyCode();
            OfcSoDetail soDetail = skuCodeMap.get(skuSupplyCode);
            if (soDetail == null) {
                throw EC.ERROR.exception("SO中不存在对应商品，供货码=" + skuSupplyCode);
            }
            BigDecimal skuSupplyPrice = soDetail.getSkuSupplyPrice();
            BigDecimal taxRate = soDetail.getTaxRate();
            detail.setSoBillCode(billCode);
            detail.setSkuCode(soDetail.getSkuCode());
            detail.setSkuSupplyPrice(skuSupplyPrice);
            detail.setSkuReturnQty(BigDecimal.ZERO);
            detail.setTaxRate(taxRate);
            detail.setVenderId(obdHead.getVenderId());

            String ext = detail.getExt();
            JSONObject extJson = new JSONObject();
            if (!StringUtils.isEmpty(ext)) {
                extJson = JSON.parseObject(ext);
            }

            extJson.put(Constants.OFC_SO_WUMART_CALLBACK_SUPPLY_PRICE, JSON.parseObject(soDetail.getExt()).getString(Constants.OFC_SO_WUMART_CALLBACK_SUPPLY_PRICE));

            detail.setExt(extJson.toJSONString());
            obdDetails.add(detail);

            BigDecimal skuDeliverQty = detail.getSkuDeliverQty();
            BigDecimal qty = obdSupplyCodeQtyMap.get(skuSupplyCode);
            if (null == qty) {
                qty = skuDeliverQty;
            } else {
                qty = qty.add(skuDeliverQty);
            }

            obdSupplyCodeQtyMap.put(skuSupplyCode, qty);
            // 构建称重品信息
            JSONObject obdDetailExt = JSON.parseObject(detail.getExt());
            // 默认给0，buildObdDetailWeightExt中会具体分析
            obdDetailExt.put(Constants.ORDER_ITEM_WEIGHT_FLAG, "0");
            Integer itemCode = 0;
            if (obdDetailExt != null) {
                Integer itemNo = obdDetailExt.getInteger("item_no");
                if (itemNo != null && itemNo.intValue() != 0) {
                    itemCode = itemNo;
                    OfcSoDetail ofcSoDetail = itemNoMap.get(itemNo);
                    if (ofcSoDetail == null) {
                        throw EC.ERROR.exception("SO中不存在对应商品，item_no=" + itemNo);
                    }
                    this.buildObdDetailWeightExt(detail, ofcSoDetail, supplySkuCodePackageWeightMap, obdDetailExt);
                } else {
                    if (fil.equals(FulfillChannel.WUMART_OFC.getValue())) {
                        itemCode = soDetail.getItemCode();
                    }
                }
            }

            if (itemCode != null) {
                detail.setItemCode(itemCode);
            } else {
                detail.setItemCode(0);
            }
            detail.setExt(obdDetailExt.toJSONString());

            BigDecimal amount = skuSupplyPrice.multiply(skuDeliverQty).setScale(6, BigDecimal.ROUND_HALF_UP);
            BigDecimal ntAmount = amount.divide(BigDecimal.ONE.add(taxRate), 6, BigDecimal.ROUND_HALF_UP);
            costAmount = costAmount.add(amount);
            costNtAmount = costNtAmount.add(ntAmount);
        }

        JSONObject obdExt = JSON.parseObject(obdHead.getExt());
        Integer wumartFill = soExt.getInteger(WumartBasicContext.WUMART_FILL);
        if (null == wumartFill) {
            wumartFill = 0;
        }
        String sumFlag = soExt.getString(Constants.ORDER_H_SUM_FLAG);
        if (StringUtils.isEmpty(sumFlag)) {
            sumFlag = SumFlag.NORMAL.getCode();
        }

        obdExt.put(Constants.OBD_H_MP_CUST_CODE, soExt.getString(Constants.SO_H_MP_CUST_CODE));
        obdHead.setExt(obdExt.toJSONString());
        obdHead.setCostAmount(costAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
        obdHead.setCostNtAmount(costNtAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
        // TODO 发货数量校验
        if (needValidateQty) {
            for (Map.Entry<String, BigDecimal> obdSupplyCodeQty : obdSupplyCodeQtyMap.entrySet()) {
                String supplyCode = obdSupplyCodeQty.getKey();
                BigDecimal obdQty = obdSupplyCodeQty.getValue();
                BigDecimal orderQty = orderSupplyCodeQtyMap.get(supplyCode);

                if (orderQty == null || obdQty.compareTo(orderQty) > 0) {
                    throw EC.SO_OBD_IS_ERROR.exception("soBillCode 单号 = " + soBillCode + " ，WMS=" + wms + " , skuSupplyCode = " + supplyCode + " , 发货数量大于订单数量");
                }
            }
        }

        // 针对称重品，且同一商品，WMS的总包重量 与 OFC分配之后总包重量的比对
        if (supplyCodeTotalWeightMap.size() > 0) {
            for (Map.Entry<String, BigDecimal> entry : supplyCodeTotalWeightMap.entrySet()) {
                String supplyCode = entry.getKey();
                BigDecimal supplyCodeQty = obdSupplyCodeQtyMap.get(supplyCode);
                logger.info("称重品，skuSupplyCode = " + supplyCode + ", 总包Qty = " + entry.getValue() + ", WMS请求Qty = " + supplyCodeQty);
                if (supplyCodeQty == null) {
                    throw EC.SO_OBD_IS_ERROR.exception("soBillCode 单号 = " + soBillCode + " ，称重数量比对，对应商品不存在！！skuSupplyCode = " + supplyCode);
                }

                if (supplyCodeQty.compareTo(entry.getValue()) != 0) {
                    throw EC.SO_OBD_IS_ERROR.exception("soBillCode 单号 = " + soBillCode + " ，WMS称重数量，与OFC分配之后，重量不相等！！skuSupplyCode = " + supplyCode + ", 总包Qty = " + entry.getValue() + ", WMS请求Qty = " + supplyCodeQty);
                }
            }
        }

        this.ofcObdDetailDAO.insertBatch(obdDetails);
        this.ofcObdHeadDAO.insert(obdHead);

        if (updateQty) {
            this.ofcBillService.insert(obdHead);
            //更新SO发货数量
            this.ofcSoService.update4Deliver(billCode, obdHead.getTotalSkuDeliverQty(), venderId);
        }
        //创建合单任务
        logger.info(uuid + ":" + orderCode + " : addTaskFlag is {} sumFlag {}", addTaskFlag, sumFlag);
        if (addTaskFlag && sumFlag.equals(SumFlag.NORMAL.getCode())) {

            OfcTask task = new OfcTask();
            task.setRefId(orderCode);
            task.setType(OfcTaskType.OBD_MERGE.getValue());
            task.setStatus(OfcTaskStatus.NEW.getValue());
            task.setVenderId(obdHead.getVenderId());

            logger.info(uuid + ":" + orderCode + " : task is " + task);
            if (this.ofcTaskService.countTask(task) <= 0 && redisTemplate.lock(MessageFormat.format(Constants.OFC_OBD_LOCK, orderCode), 10)) {
                task.setContent(orderCode.toString());
                this.ofcTaskService.addTask(task);
            }
        }

        // 添加 调用进销存po 过账  TODO 过账单位是订单 还是 obd
        logger.info(uuid + ":" + "orderCode : {}, wumartFill is {}", orderCode, wumartFill);
        if (wumartFill.equals(WumartFill.IS_NOT_WUMARKT_FILL_2_PSI.getValue())) {
            // TODO 特殊处理需要细化 2019-05-22 这个操作是在obd merger是操作的
            if (sumFlag.equals(SumFlag.SUM.getCode())) {
                BigDecimal orderQty = BigDecimal.ZERO;
                OfcObdHead obdFilter = new OfcObdHead();
                obdFilter.setOrderCode(orderCode);
                List<OfcObdHead> ofcObdHeads = this.ofcObdHeadDAO.findList(obdFilter);
                if (null != ofcObdHeads) {
                    for (OfcObdHead ofcObdHead : ofcObdHeads) {
                        orderQty = orderQty.add(ofcObdHead.getTotalSkuDeliverQty());
                    }
                }

                this.ofcOrderService.update4Deliver(orderCode, orderQty, obdHead.getVenderId());
            }

            OfcTask taskPsi = new OfcTask();
            taskPsi.setRefId(orderCode);
            taskPsi.setType(OfcTaskType.OBD_PO_PSI.getValue());
            taskPsi.setStatus(OfcTaskStatus.NEW.getValue());
            taskPsi.setVenderId(obdHead.getVenderId());

            if (this.ofcTaskService.countTask(taskPsi) <= 0 && redisTemplate.lock(MessageFormat.format(Constants.OFC_OBD_PSI_LOCK, orderCode), 10)) {
                taskPsi.setContent(orderCode.toString());
                this.ofcTaskService.addTask(taskPsi);
            }
        }

        //记录操作日志
        this.ofcOperateLogService.insert(billCode, BillType.OBD, OfcOperateEnum.OBD_RECEIVED, obdHead.getObdCode() + ":" + obdHead.getTotalSkuDeliverQty().toString(), obdHead.getVenderId());
    }

    /**
     * KG称重商品，构建ext信息
     *
     * @param obdDetail
     * @param ofcSoDetail
     * @param supplySkuCodePackageWeightMap
     * @param detailExtJson
     */
    private void buildObdDetailWeightExt(OfcObdDetail obdDetail, OfcSoDetail ofcSoDetail, Map<String, List<BigDecimal>> supplySkuCodePackageWeightMap, JSONObject detailExtJson) {
        List<BigDecimal> packageWeights = supplySkuCodePackageWeightMap.get(obdDetail.getSkuSupplyCode());
        if (packageWeights == null) {
            return;
        }

        JSONObject soDetailExt = JSON.parseObject(ofcSoDetail.getExt());
        if (soDetailExt != null) {
            Integer isWeighingGoods = soDetailExt.getInteger("is_weighing_goods");
            if (isWeighingGoods == null || isWeighingGoods.intValue() == 0) {
                return;
            }
        }

        if (packageWeights.size() == 0) {
            detailExtJson.put(Constants.OBD_D_OBD_DETAIL_EXT, "");
            obdDetail.setSkuDeliverQty(BigDecimal.ZERO);
            obdDetail.setExt(detailExtJson.toJSONString());
            return;
        }

        // 计算该行项目的销售单位
        int goodsQty = ofcSoDetail.getSkuOrderQty().divide(ofcSoDetail.getGoodsSaleUnit(), 4, BigDecimal.ROUND_HALF_UP).intValue();

        // 计算行项目的发货重量，以及拼装称重包重量
        int count = 0;
        List<String> weights = new ArrayList<>();
        BigDecimal totalDeliveryQty = BigDecimal.ZERO;
        Iterator<BigDecimal> iterator = packageWeights.iterator();
        while (iterator.hasNext()) {
            if (++count > goodsQty) {
                break;
            }
            BigDecimal packageWeight = iterator.next();
            totalDeliveryQty = totalDeliveryQty.add(packageWeight);
            weights.add(packageWeight.toString());
            // 移除该元素
            iterator.remove();
        }

        detailExtJson.put(Constants.OBD_D_OBD_DETAIL_EXT, StringUtils.collectionToDelimitedString(weights, "|"));
        detailExtJson.put(Constants.ORDER_ITEM_WEIGHT_FLAG, "1");
        obdDetail.setSkuDeliverQty(totalDeliveryQty);
    }

    /**
     * 获取KG称重品的发货称重信息
     *
     * @param obdHead
     * @return
     */
    private void dealPackageWeight(OfcObdHead obdHead, Map<String, List<BigDecimal>> supplySkuCodePackageWeightMap, Map<String, BigDecimal> supplyCodeTotalWeightMap) {
        List<OfcObdDetail> obdDtoDetails = obdHead.getDetails();

        for (OfcObdDetail obdDetail : obdDtoDetails) {
            String obdDetailExt = obdDetail.getExt();
            JSONObject detailExtJson = JSON.parseObject(obdDetailExt);
            String packageWeightStr = detailExtJson.getString(Constants.OBD_D_OBD_DETAIL_EXT);
            if (StringUtils.isEmpty(packageWeightStr) || "|".equals(packageWeightStr)) {
                continue;
            }

            String[] packageWeightArray = packageWeightStr.split("\\|");
            if (packageWeightArray != null && packageWeightArray.length > 0) {
                List<BigDecimal> packageWeightList = supplySkuCodePackageWeightMap.get(obdDetail.getSkuSupplyCode());
                if (packageWeightList == null) {
                    packageWeightList = new ArrayList<>();
                    supplySkuCodePackageWeightMap.put(obdDetail.getSkuSupplyCode(), packageWeightList);
                }

                BigDecimal totalWeight = supplyCodeTotalWeightMap.get(obdDetail.getSkuSupplyCode());
                if (totalWeight == null) {
                    totalWeight = BigDecimal.ZERO;
                }

                for (String weight : packageWeightArray) {
                    BigDecimal itemWeight = new BigDecimal(weight);
                    packageWeightList.add(itemWeight);
                    totalWeight = totalWeight.add(itemWeight);
                }

                supplyCodeTotalWeightMap.put(obdDetail.getSkuSupplyCode(), totalWeight);
            }
        }

        return;
    }


    /**
     * 判断是否需要校验"发货数量大于订单数量"
     *
     * @param so
     * @param lgortType
     * @return
     */
    private boolean needValidateQty(OfcSoHead so, Integer lgortType) {
        Integer regionCode = so.getRegionCode();
        if (regionCode > 0) {
            return false;
        }

        Integer fulfillChannel = so.getFulfillChannel();
        logger.info("是否校验发货数量：regionCode:{}, fulfillChannel:{}, lgortType:{}", new Object[]{regionCode, fulfillChannel, lgortType});
        if (fulfillChannel != null && fulfillChannel.equals(FulfillChannel.WUMART_OFC.getValue())
                && lgortType != null
                && lgortType.intValue() == LgortType.WUMART_DC.getCode()) {

            return false;
        }

        return true;
    }

    /**
     * 创建OBD信息
     *
     * @param order
     * @param addTask
     * @throws BusinessException
     */
    @Override
    public void confirm(OfcObdHead order, boolean addTask) throws BusinessException {
        Long orderCode = order.getOrderCode();
        String soBillCode = order.getSoBillCode();

        OfcObdHead update = new OfcObdHead();
        update.setTotalSkuDeliverQty(order.getTotalSkuDeliverQty());
        update.setExt(order.getExt());
        OfcObdHead filter = new OfcObdHead();
        filter.setSoBillCode(soBillCode);

        this.ofcObdHeadDAO.updateByFilter(update, filter);
        for (OfcObdDetail ofcObdDetail : order.getDetails()) {

            this.ofcObdDetailDAO.update(ofcObdDetail);
        }

        OfcObdHead ofcObdHead = ofcObdHeadDAO.findOne(filter);
        OfcObdDetail detailFilter = new OfcObdDetail();
        detailFilter.setSoBillCode(ofcObdHead.getSoBillCode());
        ofcObdHead.setDetails(ofcObdDetailDAO.findList(detailFilter));

        this.ofcBillService.insert(ofcObdHead);

        //更新SO发货数量
        this.ofcSoService.update4Deliver(soBillCode, order.getTotalSkuDeliverQty(), order.getVenderId());

        OfcTask task = new OfcTask();
        task.setType(OfcTaskType.OBD_MERGE.getValue());
        task.setStatus(OfcTaskStatus.NEW.getValue());
        task.setRefId(orderCode);

        if (this.ofcTaskService.countTask(task) <= 0 && redisTemplate.lock(MessageFormat.format(Constants.OFC_OBD_LOCK, orderCode), 10)) {
            task.setContent(orderCode.toString());
            this.ofcTaskService.addTask(task);
        }
    }

    @Override
    public int merger(Long orderCode) throws BusinessException {
        if (orderCode == null) {
            throw EC.ORDER_CODE_IS_NULL.exception();
        }

        OfcSoHead filter1 = new OfcSoHead();
        filter1.setOrderCode(orderCode);
        List<OfcSoHead> sos = this.ofcSoService.findList(filter1, true);
        if (CollectionUtils.isEmpty(sos)) {
            throw EC.SO_ORDER_NOT_EXIST.exception("订单号=" + orderCode);
        }
        BigDecimal totalSkuSupplyQty = BigDecimal.ZERO;
        Map<String, OfcSoHead> soMap = new HashMap<>(5);

        for (OfcSoHead so : sos) {
            soMap.put(so.getSoBillCode(), so);
            totalSkuSupplyQty = totalSkuSupplyQty.add(so.getTotalSkuSupplyQty());
        }

        int soSize = soMap.size();
        logger.info("SO集合：" + soMap.keySet());

        OfcObdHead filter2 = new OfcObdHead();
        filter2.setOrderCode(orderCode);
        List<OfcObdHead> obds = this.findList(filter2, true);
        if (CollectionUtils.isEmpty(obds)) {
            throw EC.SO_OBD_NOT_EXIST.exception("订单号=" + orderCode);
        }
        BigDecimal totalSkuDeliverQty = BigDecimal.ZERO;
        Map<String, OfcObdHead> obdMap = new HashMap<>();
        for (OfcObdHead obd : obds) {
            obdMap.put(obd.getSoBillCode(), obd);
            totalSkuDeliverQty = totalSkuDeliverQty.add(obd.getTotalSkuDeliverQty());
        }
        int obdSize = obdMap.size();
        logger.info("【" + orderCode + "】OBD集合：" + obdMap.keySet());

        boolean flag = (soSize == obdSize);
        if (!flag) {
            logger.warn("【" + orderCode + "】有部分SO尚未发货！");
            for (OfcObdHead obd : obds) {
                int createTime = obd.getCreateTime().intValue();
                if (OFCUtils.currentTime() - createTime > 600) {
                    logger.warn("【" + orderCode + "】有部分SO尚未发货，但已超过10分钟，直接发货！");
                    flag = true;
                }
            }
        }

        if (!flag) {
            logger.warn("【" + orderCode + "】有部分SO尚未发货，不触发发货异步操作！");
            return 0;
        }

        BigDecimal totalOrderRespQty = BigDecimal.ZERO;

        for (OfcSoHead so : sos) {
            totalOrderRespQty = totalOrderRespQty.add(so.getTotalSkuSupplyQty());
        }

        if (!this.redisTemplate.lock(orderCode.toString(), 30)) {
            return 0;
        }

        OfcSoHead so = sos.get(0);
        JSONObject soExtJson = JSON.parseObject(so.getExt());
        Integer deliveryType = soExtJson.getInteger("deliveryType");
        Integer saleModel = soExtJson.getInteger("saleModel");

        OfcOrderHead filter = new OfcOrderHead();
        filter.setOrderCode(orderCode);
        OfcOrderHead head = ofcOrderService.findOne(filter, false);

        JSONObject extJson = JSON.parseObject(head.getExt());
        Integer logisticsMode = extJson.getInteger("logisticsMode");

        try {
            BigDecimal amount = BigDecimal.ZERO;
            BigDecimal ntAmount = BigDecimal.ZERO;
            List<String> soCodes = new ArrayList<>();
            List<String> obdCodes = new ArrayList<>();
            List<String> soBillCodes = new ArrayList<>();
            JSONObject json = new JSONObject();
            json.put("system", Constants.OFC_BILL_SYSTEM_WUMART_SAP);
            json.put("type", BillType.OBD.name());
            json.put("order_id", orderCode.toString());
            //箱数
            int boxNum = 0;
            //周转箱数
            int turnoverBoxNum = 0;
            //散箱数
            BigDecimal scatteredBoxNum = BigDecimal.ZERO;
            JSONArray items = new JSONArray();
            Set<String> warehouseIds = new HashSet<>();
            Set<String> warehouseNames = new HashSet<>();
            Set<String> supplierDcs = new HashSet<>();
            Set<Integer> supplierIds = new HashSet<>();
            BigDecimal orderTotalVolume = BigDecimal.ZERO;
            Long venderId = null;
            Set<String> collectCodes = new HashSet<>(5);
            int receiptFlag = 0;
            for (OfcObdHead obd : obds) {
                JSONObject hext = JSON.parseObject(obd.getExt());
                amount = amount.add(obd.getCostAmount());
                ntAmount = ntAmount.add(obd.getCostNtAmount());
                String waybillId = hext.getString(Constants.OBD_H_WAYBILL_CODE);
                String driverInfo = hext.getString(Constants.OBD_H_DRIVER_INFO);
                boxNum += NumberUtils.toInt(hext.getString(Constants.OBD_H_BOX_NUM), 0);
                int turnoverBoxNumTemp = NumberUtils.toInt(hext.getString(Constants.OBD_H_TURNOVER_BOX_NUM), 0);

                if (turnoverBoxNumTemp > 0) {
                    turnoverBoxNum += turnoverBoxNumTemp;
                }

                receiptFlag = hext.getIntValue(Constants.OBD_D_OBD_RECEIPT_FLAG);
                collectCodes.add(hext.getString("collect_code"));

                venderId = obd.getVenderId();

                BigDecimal scatteredBoxNumTemp = new BigDecimal(ObjectUtils.toString(hext.getString(Constants.OBD_H_SCATTERED_BOX_NUM), "0.00"));
                if (scatteredBoxNumTemp.compareTo(BigDecimal.ZERO) > 0) {
                    scatteredBoxNum = scatteredBoxNum.add(scatteredBoxNumTemp);
                }

                BigDecimal obdtotalVolume = new BigDecimal(ObjectUtils.toString(hext.getString(Constants.OBD_TOTAL_VOLUME), "0.00"));
                if (obdtotalVolume.compareTo(BigDecimal.ZERO) > 0) {

                    orderTotalVolume = orderTotalVolume.add(obdtotalVolume);
                }

                soCodes.add(obd.getSoCode());
                obdCodes.add(obd.getObdCode());
                soBillCodes.add(obd.getSoBillCode());

                supplierIds.add(obd.getSupplierId());
                supplierDcs.add(obd.getSupplierDc());
                warehouseIds.add(obd.getWarehouseCode());
                warehouseNames.add(obd.getWarehouseName());
                json.put("waybill_id", waybillId);
                json.put("driver_info", driverInfo);
                json.put("car_type", hext.getString(Constants.OBD_H_VEHICLE_TYPE));
                json.put("car_type_desc", hext.getString(Constants.OBD_H_VEHICLE_TYPE_DESC));
                json.put("carrier_code", hext.getString(Constants.OBD_H_CARRIER_CODE));
                json.put("carrier_name", hext.getString(Constants.OBD_H_CARRIER_NAME));
                json.put("create_time", hext.getString(Constants.OBD_H_CREATE_TIME));
                json.put("pick_time", hext.getString(Constants.OBD_H_PICK_TIME));
                json.put("delivery_time", hext.getString(Constants.OBD_H_DELIVERY_TIME));
                json.put("so_user_id", hext.getString(Constants.OBD_H_MP_CUST_CODE));
                for (OfcObdDetail detail : obd.getDetails()) {
                    JSONObject item = new JSONObject();
                    JSONObject dext = JSON.parseObject(detail.getExt());
                    item.put("code", detail.getSkuSupplyCode());
                    item.put("item_id", detail.getSkuCode());
                    item.put("qty", detail.getSkuDeliverQty().toString());
                    item.put("waybill_id", waybillId);
                    item.put("driver_info", driverInfo);
                    item.put("pack_num", dext.getString(Constants.OBD_D_PACK_NUM));
                    item.put("box_num", dext.getString(Constants.OBD_D_BOX_NUM));
                    item.put("left_ea_num", dext.getString(Constants.OBD_D_LEFT_EA_NUM));
                    item.put("obd_detail_ext", dext.getString(Constants.OBD_D_OBD_DETAIL_EXT));
                    item.put("sku_define", dext.getString(Constants.OBD_D_OBD_DETAIL_DEFINE));
                    item.put("so_code", obd.getSoCode());
                    item.put("supplier_org", obd.getSupplierOrg());
                    item.put("sku_name", dext.getString(Constants.OBD_D_OBD_SKU_NAME));
                    item.put("barcode", dext.getString(Constants.OBD_D_OBD_BARCODE));
                    item.put("pack_code", dext.getString(Constants.OBD_D_OBD_PACK_CODE));
                    item.put("weight", dext.getString(Constants.OBD_D_OBD_SKU_WEIGHT));

                    items.add(item);
                }
            }

            json.put("warehouse_id", StringUtils.collectionToDelimitedString(warehouseIds, "|"));
            json.put("warehouse_name", StringUtils.collectionToDelimitedString(warehouseNames, "|"));
            json.put("out_order_id", StringUtils.collectionToDelimitedString(soCodes, ","));
            json.put("bill_id", StringUtils.collectionToDelimitedString(obdCodes, ","));
            json.put("collect_code", StringUtils.collectionToDelimitedString(collectCodes, ","));
            json.put("provider_id", StringUtils.collectionToDelimitedString(supplierIds, "|"));
            json.put("order_dc", StringUtils.collectionToDelimitedString(supplierDcs, "|"));
            json.put("box_num", boxNum);
            json.put("turnoverbox_num", turnoverBoxNum);
            json.put("scattered_box_num", scatteredBoxNum.toString());
            json.put(Constants.OBD_TOTAL_VOLUME, orderTotalVolume.toString());
            json.put("amount", amount.toString());
            json.put("nt_amount", ntAmount.toString());
            json.put("lack_num", totalSkuDeliverQty.subtract(totalSkuSupplyQty));
            json.put("sale_model", saleModel);
            json.put("delivery_type", deliveryType);
            json.put("obd_ext", "{}");
            json.put("items", items);

            JSONObject address = JSON.parseObject(head.getAddressInfo());
            String duoDianOrder = address.getString("DuoDianOrder");

            if (!StringUtils.isEmpty(duoDianOrder) && duoDianOrder.equals("1")) {
                receiptFlag = 1;
            }

            json.put(Constants.OBD_D_OBD_RECEIPT_FLAG, receiptFlag);
            json.put("obd_order_picking_info", "{}");
            Boolean shippingFlag = this.omsServiceProxy.createReceipt(json);
                logger.info("oms 发货处理 ：" + shippingFlag);

            if (shippingFlag) {
                this.ofcOrderService.update4Deliver(orderCode, totalSkuDeliverQty, venderId);
            }

            if (shippingFlag) {
                return sos.size();
            } else {
                return -1;
            }

        } finally {
            this.redisTemplate.unlock(orderCode.toString());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BigDecimal update4Return(String billCode, Map<Long, BigDecimal> returnQtyMap) throws BusinessException {
        BigDecimal sum = BigDecimal.ZERO;
        for (Map.Entry<Long, BigDecimal> entry : returnQtyMap.entrySet()) {
            BigDecimal qty = entry.getValue();
            int ret = this.ofcObdDetailDAO.update4Return(billCode, entry.getKey(), qty);
            if (ret != 1) {
                throw EC.ERROR.exception("更新OBD明细返仓数量失败！单号=" + billCode + "，ID=" + entry.getKey() + "，QTY=" + qty);
            }
            sum = sum.add(qty);
        }
        int ret = this.ofcObdHeadDAO.update4Return(billCode, sum);
        if (ret != 1) {
            throw EC.ERROR.exception("更新OBD返仓数量失败！单号=" + billCode + "，QTY=" + sum);
        }
        return sum;
    }

    /**
     * 更新OBD信息(返仓)
     *
     * @param billCode
     * @param ext
     * @return
     * @throws BusinessException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update4ext(String billCode, String ext) throws BusinessException {

        OfcObdHead filter = new OfcObdHead();
        filter.setSoBillCode(billCode);

        OfcObdHead update = new OfcObdHead();
        update.setExt(ext);

//        this.addOrUpdateTask(Long.valueOf(billCode));

        return this.ofcObdHeadDAO.updateByFilter(update, filter);
    }

    /**
     * 根据包裹数量，生成相应数量的包裹编码
     * 生成策略：soBillCode-编码； 例如：soBillCode-1、soBillCode-2、soBillCode-3
     *
     * @return
     */
    @Override
    public List<String> generatePackageCodes(String soBillCode, Integer packageNum) {
        if (packageNum == null || packageNum.intValue() == 0) {
            return new ArrayList<>();
        }
        List<String> packageCodes = new ArrayList<>(packageNum);
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= packageNum; i++) {
//            sb.append(soBillCode).append("-").append(i);
            // todo：此处指保留包裹编号，省略前缀，待使用时，再拼装；以减少存储空间的占用
            sb.append(i).append("A");
            packageCodes.add(sb.toString());
            sb.setLength(0);
        }

        return packageCodes;
    }

    @Override
    public String buildPackageCodes(PackageCodeBo packageCodeBo) {
        int taskModel = packageCodeBo.getTaskModel().intValue();
        if (taskModel == 2) {
            return packageCodeBo.getSupplyId() + Constants.MIDDLE_LINE
                    + packageCodeBo.getSkuCode() + Constants.MIDDLE_LINE
                    + packageCodeBo.getSaleUnit().setScale(2, BigDecimal.ROUND_HALF_UP).toString() + "B";
        } else {
            return packageCodeBo.getSoBillCode() + Constants.MIDDLE_LINE + packageCodeBo.getPackageNo();
        }
    }


    private String buildPC4WG(OfcObdHead obdHead) {
        JSONObject head = new JSONObject();
        head.put("po_id", obdHead.getOrderCode());
        head.put("wm_order_id", obdHead.getSoCode());

        int i = 1;
        JSONArray items = new JSONArray();
        for (OfcObdDetail detail : obdHead.getDetails()) {
            JSONObject item = new JSONObject();
            item.put("line_no", 10 * i++);
            item.put("goods_id", detail.getSkuSupplyCode());
            item.put("qty", detail.getSkuDeliverQty());
            items.add(item);
        }
        head.put("items", items);

        return head.toJSONString();
    }

    private void insertObd2DmallTask(Long orderCode) {
        OfcTask task = new OfcTask();
        task.setRefId(orderCode);
        task.setType(OfcTaskType.STO_OBD_DMALL.getValue());
        task.setStatus(OfcTaskStatus.NEW.getValue());
        task.setContent(String.valueOf(orderCode));
        ofcTaskService.addTask(task);
    }

}
